<?php

abstract class Base
{
  protected static $modx = null;
  protected static function modx() {
    if (!Base::$modx) {global $modx; Base::$modx = $modx;}
    return Base::$modx;
  }

  protected static abstract function schema();
  protected abstract static function instantiate($array_of_attributes);

  /**
   * Map properties to either accessor methods or $this->fields
   */
  function __get($name) {
    return (method_exists($this, $name) ?
     call_user_func(array($this, $name)) : $this->fields[$name]);
  }

  function __put($name, $value) {
    $accessor = 'set_'.$name;

    return ($method_exists($this, $accessor) ?
     call_user_func(array($this, $accessor)) : $this->$fields[$name] = $value);
  }

  function find_by_id($id) {
    $modx = Base::modx();
    $schema = $this->schema();

    $result = $modx->db->select('*',
     $schema->table . ' t1 ',
     't1.'.$schema->primary_key. ' = ' .$modx->db->escape($id));

    return Base::instantiate($modx->db->makeArray($result));
  }
}

class Schema
{
  protected $protected_attrs = array();

  public function Schema($table_name, $array_of_columns, $modx = null) {
    $this->table = $table_name;
    $this->columns = $array_of_columns;
  }
}


class WebUser extends Base
{
  protected static function schema() { return WebUser::$Schema; }
  protected static function instantiate($array_of_attributes) {
    return new WebUser($array_of_attributes);
  }

  public function WebUser($array_of_attributes) {
    $this->Base($array_of_attributes);
  }

  # has_one web_user_attributes
  # has_many web_user_groups
  # has_one customer
}

WebUser::$Schema = new Schema('web_users', array());

class Transaction extends Base
{
  protected static function schema() { return Order::$Schema; }
  protected static function instantiate($array_of_attributes) {
    return new Transaction($array_of_attributes);
  }

  public function Transaction($array_of_attributes) {
    $this->Base($array_of_attributes);
  }

  # belongs to customer
}

Order::$Schema = new Schema('transactions', array());

?>
